package com.tool.cn.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



/**
 * 
 * @author wangzonghui
 * @date 2021-08-03 15:53:09
 * @Description shell 执行返回状态值
 */
public final class ShellUtil{

	private static Logger log= LoggerFactory.getLogger(ShellUtil.class);
	
	private static ShellUtil getIntShell=new ShellUtil();
	
	private ShellUtil() {}
	
	public static ShellUtil getInstance() {
		return getIntShell;
	}

	//不判定超时
	public int submitSH(String cmd) {
		
		Process ps = null;
		int exitCode = -1;
		try {
			ps = Runtime.getRuntime().exec(new String[] { "bash", "-c", cmd });
			
			
			exitCode = ps.waitFor();
			
			
			if (exitCode != 0) {
				 InputStream errorStream = ps.getErrorStream();
				 BufferedReader br = new BufferedReader(new InputStreamReader(errorStream));
				 String errContext="",line;
                 while (true){
                     line = br.readLine();
                     if(line == null) break;
                     errContext+=line;
                 }
                 
				log.error(cmd+" run is error code:"+ exitCode+" "+errContext);
			}
			
		} catch (Exception e) {
			log.error("Shell run InterruptedException:"+cmd, e);
		} finally {
			if (null != ps)
				ps.destroy();
		}
		return exitCode;
	}
	
	/**
	 * 执行命令
	 * @param cmd
	 * @param outtime 超时时间单位毫秒
	 * @return
	 */
	public int submitSH(String cmd,int outtime){
		
		Process ps=null;
		int exitCode = -1;
		try {
			
			ps = Runtime.getRuntime().exec(new String[] { "bash", "-c", cmd });
			ProcessWithTimeout processWithTimeout = new ProcessWithTimeout(ps);
			exitCode = processWithTimeout.waitForProcess(outtime);
			
			if (exitCode == Integer.MIN_VALUE)
			{
			 exitCode=1;
			 log.error(cmd+" Run is Timeout!");
			}
			
			if (exitCode != 0) {
				 InputStream errorStream = ps.getErrorStream();
				 BufferedReader br = new BufferedReader(new InputStreamReader(errorStream));
				 String errContext="",line;
                 while (true){
                     line = br.readLine();
                     if(line == null) break;
                     errContext+=line;
                 }
				
				log.error(cmd+" run is error code:"+ exitCode+" "+errContext);
			}
			
		} catch (Exception e) {
			log.error("Shell run IOException:"+cmd, e);
		} finally {
			if (null != ps)
				ps.destroy();
		}
		return exitCode;
	}

	/**
	 * 超时监控线程
	 * 
	 * @author wangzh
	 * 2017年7月4日 下午4:05:14
	 */
	class ProcessWithTimeout extends Thread{
		
		private Process m_process;
		private int m_exitCode = Integer.MIN_VALUE;
		 
		public ProcessWithTimeout(Process p_process){
			 m_process = p_process;
		}
		 
		public int waitForProcess(int outtime){
			  this.start();
			  
			  try{
			     this.join(outtime);
			  }catch (InterruptedException e){
			   log.error("Wait Is Error",e);
			  }
			  
			  return m_exitCode;
		 }
		 
		 @Override
		 public void run(){
		  try{ 
		     m_exitCode = m_process.waitFor();
		     
		  } catch (Exception e){
		  	 log.error("Warit Is Error",e);
		  }
		 }

	}
	
	/**
	 * 执行命令返回状态和信息
	 * @param cmd 命令
	 * @param fileList 控制台信息
	 * @return 状态
	 */
	public int submitSH(String cmd,List<String> fileList) {
		Process proc = null;
		int exitCode = -1;
		TrackConsoleMsg trackInf = null;
		try { // log.info("shellCMD=" + cmd);
			proc = new ProcessBuilder("bash", "-c", cmd).start();

			trackInf = new TrackConsoleMsg(proc.getInputStream(), fileList);
			trackInf.start();
			exitCode = proc.waitFor();
			
			if (exitCode != 0 && exitCode != 2) {
				 InputStream errorStream = proc.getErrorStream();
				 BufferedReader br = new BufferedReader(new InputStreamReader(errorStream));
				 String errContext="",line;
                 while (true){
                     line = br.readLine();
                     if(line == null) break;
                     errContext+=line;
                 }
				log.error(cmd+" run is error code:"+ exitCode+" "+errContext);
				return exitCode;
			}
			
			trackInf.join();
			
		} catch (Exception e) {
			log.error("Shell run InterruptedException:", e);
		} finally {
			if (null != proc)
				proc.destroy();
		}
		return exitCode;
	}
	
	class TrackConsoleMsg extends Thread {
		private BufferedReader read = null;
		private List<String> list = null;

		public TrackConsoleMsg(InputStream in, List<String> list) {
			read = new BufferedReader(new InputStreamReader(in));
			this.list = list;
		}

		@Override
		public void run() {
			String line = null;
			try {
				line = read.readLine();
				while (null != line && !isInterrupted()) {
					if (line.indexOf("ls: cannot access") < 0) {
						list.add(line);
					}
					line = read.readLine();
				}
			} catch (Exception e) {
				log.error("Shell Read console error:", e);
			} finally {
				if (null != read) {
					try {
						read.close();
					} catch (IOException e) {
						log.error("Shell Read console error:", e);
					}
				}
			}
		}
	}

}
